/*
* Copyright (c) Microsoft Corporation.  All Rights Reserved.
*
* Represents a detoured function
*/
#pragma once
#include "Mock10.h"
#include "Functor.h"
#include "DetourFilterInfo.h"

#pragma push_macro("Assert")
#undef Assert

#pragma push_macro("SEALED")
#undef SEALED

#if _MSC_VER >= 1400
# define SEALED sealed
#else
# define SEALED
#endif

namespace WEX { namespace Common 
{
    class DebugHelp;
    class FunctionDebugTypeInfo;

    template <typename T>
    class PtrRefCount;
}}

namespace Mock10 { namespace Private
{
    class TargetFunctionInfoArray;

    class MOCK10_API MockStatus
    {
    public:
        explicit MockStatus(HRESULT hr);
        MockStatus(HRESULT hr, const wchar_t* pszMessage);
        MockStatus(const MockStatus& other);
        MockStatus& operator=(const MockStatus& other);
        ~MockStatus();

        void Set(HRESULT hr, const wchar_t* pszMessage = NULL);

        // wchar_t native type exports
        #if defined(MOCK10_FULL_BUILD)
        MockStatus(HRESULT hr, const __wchar_t* pszMessage);
        void Set(HRESULT hr, const __wchar_t* pszMessage = NULL);
        #endif

        const unsigned short* GetMessage() const; // Return unsigned short* here; otherwise we'd need to create both wchar_t* and __wchar_t* versions that return the value as an out parameter
        HRESULT GetErrorCode() const;

    private:
        HRESULT m_status;

        struct Impl;
        Impl* m_pImpl;
    };

    MOCK10_API MockStatus __stdcall ResolveQuery(const wchar_t* pszTargetBinary, const wchar_t* pszTargetQuery, TargetFunctionInfoArray& targetFunctions, 
                                                 void* pTargetClass, WEX::Common::DebugHelp& debugHelpInstance);
    MOCK10_API MockStatus __stdcall TrimUnneeded(TargetFunctionInfoArray& targetFunctions, void* pDetourFunction, void* pShimFunction, 
                                                 WEX::Common::DebugHelp& inProcDebugHelpInstance);

    // wchar_t native type exports
    #if defined(MOCK10_FULL_BUILD)
    MOCK10_API MockStatus __stdcall ResolveQuery(const __wchar_t* pszTargetBinary, const __wchar_t* pszTargetQuery, TargetFunctionInfoArray& targetFunctions, 
                                                 void* pTargetClass, WEX::Common::DebugHelp& debugHelpInstance);
    #endif

    class MOCK10_API TargetFunctionInfo
    {
    template <typename T>
    friend class WEX::Common::PtrRefCount;

    public:
        void* GetAddress() const;
        long GetThisAdjust() const;
        WEX::Common::PtrRefCount<WEX::Common::FunctionDebugTypeInfo>& GetFunctionTypeInfo();
        const unsigned short* GetName(); // Return unsigned short* here; otherwise we'd need to create both wchar_t* and __wchar_t* versions that return the value as an out parameter

        explicit TargetFunctionInfo(void* pTarget);
        TargetFunctionInfo(void* pTarget, long thisAdjust);
        TargetFunctionInfo(void* pTargetClass, WEX::Common::PtrRefCount<WEX::Common::FunctionDebugTypeInfo>& spFunctionTypeInfo, WEX::Common::DebugHelp& debugHelpInstance);
        ~TargetFunctionInfo();

    private:
        TargetFunctionInfo& operator=(const TargetFunctionInfo&); // Not implemented
        TargetFunctionInfo(const TargetFunctionInfo&); // Not implemented

        unsigned long AddRef();
        unsigned long Release();

        volatile long m_refCount;

        struct Impl;
        Impl* m_pImpl;
    };

    class MOCK10_API TargetFunctionInfoArray SEALED
    {
    public:
        TargetFunctionInfoArray();
        TargetFunctionInfoArray(size_t size);
        ~TargetFunctionInfoArray();

        HRESULT GetStatus() const;
        size_t GetCount() const;
        TargetFunctionInfo* GetAt(size_t index) const;
        void Add(void* pTarget, long thisAdjust = 0);

        struct Impl;
        Impl* m_pImpl;

    private:
        TargetFunctionInfoArray& operator=(const TargetFunctionInfoArray&); // Not implemented
        TargetFunctionInfoArray(const TargetFunctionInfoArray&); // Not implemented

        HRESULT m_status;
    };

    class __declspec(novtable) MOCK10_API DetourFunctionBase
    {
    friend class DetourInfo;

    public:
        virtual ~DetourFunctionBase();

        const MockStatus& GetStatus() const;

        long GetParameterIndex(const wchar_t* pszParameterName) const;
        long GetThisAdjust() const;
        void* GetTarget() const;

    protected:
        DetourFunctionBase(TargetFunctionInfo& targetFunctionInfo);
        void SetFilterImpl(const wchar_t* pszFilter);

        // wchar_t native type exports
        #if defined(MOCK10_FULL_BUILD)
        void SetFilterImpl(const __wchar_t* pszFilter);
        #endif

        bool FilterMatches(const DetourFilterInfoBase& filterInfo) const;

        MockStatus m_status;
        void* m_pTargetFunction;

    private:
        struct Impl;
        Impl* m_pImpl;
    };

    template <typename TPrototype, typename TDetourPrototype, typename TDerived>
    class DetourFunctionImpl : public DetourFunctionBase
    {
    public:
        // Construct from a function pointer for the detour
        DetourFunctionImpl(TargetFunctionInfo& targetFunctionInfo, TDetourPrototype* pDetourFunction)
            : DetourFunctionBase(targetFunctionInfo)
            , m_attached(false)
        {
            if (!targetFunctionInfo.GetAddress())
            {
                m_status.Set(E_POINTER);
            }
            else if (targetFunctionInfo.GetAddress() == reinterpret_cast<void*>(pDetourFunction))
            {
                m_status.Set(E_INVALIDARG);
            }
            else if (pDetourFunction)
            {
                // Create a functor for the detour function and register ourselves with the detour manager
                Attach(pDetourFunction);
            }
        }

        // Construct from an existing WEX::Common::Functor object for the detour
        DetourFunctionImpl(TargetFunctionInfo& targetFunctionInfo, const WEX::Common::Functor<TDetourPrototype>& detourFunctor)
            : DetourFunctionBase(targetFunctionInfo)
            , m_attached(false)
        {
            if (!targetFunctionInfo.GetAddress())
            {
                m_status.Set(E_POINTER);
            }
            #pragma warning(push)
            #pragma warning(disable: 4127)
            else if (WEX::Common::AreSameType<TPrototype, TDetourPrototype>::value && WEX::Common::Functor<TPrototype>(static_cast<TPrototype*>(targetFunctionInfo.GetAddress())) == detourFunctor)
            {
                m_status.Set(E_INVALIDARG);
            }
            #pragma warning(pop)
            else
            {
                Attach(detourFunctor);
            }
        }

        virtual ~DetourFunctionImpl()
        {
            MockStatus result = Detach();
            WEX_ASSERT(SUCCEEDED(result.GetErrorCode()), L"");
        }

        // Supports replacing with either raw function pointers or existing WEX::Common::Functor objects
        template <typename TDetourFunction>
        void Replace(const TDetourFunction& detourFunction)
        {
            if (SUCCEEDED(m_status.GetErrorCode()))
            {
                // Users can specify null to cancel the Detour
                if (PrivateUtilities::IsDetourInValid(detourFunction))
                {
                    m_status = Detach();
                }
                else
                {
                    Attach(detourFunction);
                }
            }
        }

        void SetFilter(const wchar_t* pszFilter)
        {
            if (SUCCEEDED(m_status.GetErrorCode()))
            {
                // Enter critical section and set the filter
                WriteCriticalSectionLock lock(Detour::GetGlobalCriticalSection());
                SetFilterImpl(pszFilter);
            }
        }

        TPrototype* GetTarget() const
        {
            return static_cast<TPrototype*>(m_pTargetFunction);
        }

        #define DETOUR_FILTER_NAMED_ARGS_0 
        #define DETOUR_FILTER_NAMED_ARGS_1 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1
        #define DETOUR_FILTER_NAMED_ARGS_2 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2
        #define DETOUR_FILTER_NAMED_ARGS_3 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3
        #define DETOUR_FILTER_NAMED_ARGS_4 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4
        #define DETOUR_FILTER_NAMED_ARGS_5 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5
        #define DETOUR_FILTER_NAMED_ARGS_6 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter6>::Result p6
        #define DETOUR_FILTER_NAMED_ARGS_7 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter7>::Result p7
        #define DETOUR_FILTER_NAMED_ARGS_8 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter8>::Result p8
        #define DETOUR_FILTER_NAMED_ARGS_9 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter9>::Result p9
        #define DETOUR_FILTER_NAMED_ARGS_10 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter10>::Result p10
        #define DETOUR_FILTER_NAMED_ARGS_11 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter11>::Result p11
        #define DETOUR_FILTER_NAMED_ARGS_12 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter12>::Result p12
        #define DETOUR_FILTER_NAMED_ARGS_13 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter13>::Result p13
        #define DETOUR_FILTER_NAMED_ARGS_14 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter13>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter14>::Result p14
        #define DETOUR_FILTER_NAMED_ARGS_15 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter13>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter14>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter15>::Result p15
        #define DETOUR_FILTER_NAMED_ARGS_16 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter13>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter14>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter15>::Result p15, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter16>::Result p16
        #define DETOUR_FILTER_NAMED_ARGS_17 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter13>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter14>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter15>::Result p15, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter16>::Result p16, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter17>::Result p17
        #define DETOUR_FILTER_NAMED_ARGS_18 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter13>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter14>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter15>::Result p15, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter16>::Result p16, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter17>::Result p17, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter18>::Result p18
        #define DETOUR_FILTER_NAMED_ARGS_19 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter13>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter14>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter15>::Result p15, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter16>::Result p16, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter17>::Result p17, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter18>::Result p18, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter19>::Result p19
        #define DETOUR_FILTER_NAMED_ARGS_20 , typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter13>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter14>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter15>::Result p15, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter16>::Result p16, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter17>::Result p17, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter18>::Result p18, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter19>::Result p19, typename WEX::Common::MakeReference<typename WEX::Common::Functor<TPrototype>::Parameter20>::Result p20

        #define DETOUR_FILTER_ARGS_0 
        #define DETOUR_FILTER_ARGS_1 , p1
        #define DETOUR_FILTER_ARGS_2 , p1, p2
        #define DETOUR_FILTER_ARGS_3 , p1, p2, p3
        #define DETOUR_FILTER_ARGS_4 , p1, p2, p3, p4
        #define DETOUR_FILTER_ARGS_5 , p1, p2, p3, p4, p5
        #define DETOUR_FILTER_ARGS_6 , p1, p2, p3, p4, p5, p6
        #define DETOUR_FILTER_ARGS_7 , p1, p2, p3, p4, p5, p6, p7
        #define DETOUR_FILTER_ARGS_8 , p1, p2, p3, p4, p5, p6, p7, p8
        #define DETOUR_FILTER_ARGS_9 , p1, p2, p3, p4, p5, p6, p7, p8, p9
        #define DETOUR_FILTER_ARGS_10 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10
        #define DETOUR_FILTER_ARGS_11 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11
        #define DETOUR_FILTER_ARGS_12 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12
        #define DETOUR_FILTER_ARGS_13 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13
        #define DETOUR_FILTER_ARGS_14 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14
        #define DETOUR_FILTER_ARGS_15 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15
        #define DETOUR_FILTER_ARGS_16 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16
        #define DETOUR_FILTER_ARGS_17 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17
        #define DETOUR_FILTER_ARGS_18 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18
        #define DETOUR_FILTER_ARGS_19 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19
        #define DETOUR_FILTER_ARGS_20 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20

        #define DETOUR_FILTER_METHOD(PARAMCOUNT) \
        bool FilterMatches(const void* pReturnAddress BUILD_VARIABLE_NAME(DETOUR_FILTER_NAMED_ARGS_, PARAMCOUNT)) \
        { \
            AutoDisableDetours disable; \
            DetourFilterInfo<TPrototype> filterInfo(*this, pReturnAddress BUILD_VARIABLE_NAME(DETOUR_FILTER_ARGS_, PARAMCOUNT)); \
            return __super::FilterMatches(filterInfo); \
        }

        // Builds out each Filter(...) method that gets invoked by the DetourShim
        DETOUR_FILTER_METHOD(0)
        DETOUR_FILTER_METHOD(1)
        DETOUR_FILTER_METHOD(2)
        DETOUR_FILTER_METHOD(3)
        DETOUR_FILTER_METHOD(4)
        DETOUR_FILTER_METHOD(5)
        DETOUR_FILTER_METHOD(6)
        DETOUR_FILTER_METHOD(7)
        DETOUR_FILTER_METHOD(8)
        DETOUR_FILTER_METHOD(9)
        DETOUR_FILTER_METHOD(10)
        DETOUR_FILTER_METHOD(11)
        DETOUR_FILTER_METHOD(12)
        DETOUR_FILTER_METHOD(13)
        DETOUR_FILTER_METHOD(14)
        DETOUR_FILTER_METHOD(15)
        DETOUR_FILTER_METHOD(16)
        DETOUR_FILTER_METHOD(17)
        DETOUR_FILTER_METHOD(18)
        DETOUR_FILTER_METHOD(19)
        DETOUR_FILTER_METHOD(20)

    protected:
        WEX::Common::Functor<TDetourPrototype> m_detourFunction;

    private:
        // Supports attaching with either a raw function pointer or an existing WEX::Common::Functor object
        template <typename TFunction>
        void Attach(const TFunction& function)
        {
            if (SUCCEEDED(m_status.GetErrorCode()))
            {
                // Enter critical section
                WriteCriticalSectionLock lock(Detour::GetGlobalCriticalSection());
                AutoDisableDetours disable;

                // Make sure we are able to attach (or are already attached) before we set m_detourFunction
                if (!m_attached)
                {
                    m_status = DetourManager<TPrototype, TDerived>::Attach(static_cast<TPrototype*>(m_pTargetFunction), static_cast<TDerived*>(this));
                    m_attached = SUCCEEDED(m_status.GetErrorCode());
                }
                
                if (SUCCEEDED(m_status.GetErrorCode()))
                {
                    #if defined(_CPPUNWIND)
                    try
                    {
                    #endif
                        // This assignment allocates an object on the heap, so it can throw if exceptions are enabled
                        m_detourFunction = WEX::Common::Functor<TDetourPrototype>(function);
                    #if defined(_CPPUNWIND)
                    }
                    catch (...)
                    {
                        // We need to catch any exception that is thrown when allocating the functor object, and detach if this ever occurs
                        // Otherwise, we will AV the next time the target function is invoked by a third party
                        Detach();
                        throw;
                    }
                    #endif
                }
            }
        }

        MockStatus Detach()
        {
            // Enter critical section
            WriteCriticalSectionLock lock(Detour::GetGlobalCriticalSection());
            AutoDisableDetours disable;

            // Detach whether or not we're in a succeeded state
            // We must be careful to clear our state *after* the Detach() call is made
            MockStatus result = DetourManager<TPrototype, TDerived>::Detach(static_cast<TPrototype*>(m_pTargetFunction), static_cast<TDerived*>(this));
            if (SUCCEEDED(result.GetErrorCode()))
            {
                m_detourFunction.Clear();
                m_attached = false;
            }

            return result;
        }

        struct PrivateUtilities
        {
            static bool IsDetourInValid(const WEX::Common::Functor<TDetourPrototype>& detourFunctor)
            {
                return !detourFunctor.IsValid();
            }

            template <typename TDetourFunction>
            static bool IsDetourInValid(TDetourFunction* pDetourFunction)
            {
                return !pDetourFunction;
            }
        };

        bool m_attached;
    };

    template <typename TPrototype, typename TDetourPrototype = TPrototype>
    class DetourFunction: public DetourFunctionImpl<TPrototype, TDetourPrototype, DetourFunction<TPrototype, TDetourPrototype>>
    {
    template <typename TPrototype, typename TDetourFunction>
    friend struct DetourShim; // For access to detour 'Function' methods

    public:
        // Construct from a function pointer for the detour
        DetourFunction(TargetFunctionInfo& targetFunctionInfo, TDetourPrototype* pDetourFunction)
            : DetourFunctionImpl(targetFunctionInfo, pDetourFunction)
        {
        }

        // Construct from an existing WEX::Common::Functor object for the detour
        DetourFunction(TargetFunctionInfo& targetFunctionInfo, const WEX::Common::Functor<TDetourPrototype>& detourFunctor)
            : DetourFunctionImpl(targetFunctionInfo, detourFunctor)
        {
        }

    private:
        #define DETOUR_NAMED_ARGS_0 
        #define DETOUR_NAMED_ARGS_1 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1
        #define DETOUR_NAMED_ARGS_2 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2
        #define DETOUR_NAMED_ARGS_3 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3
        #define DETOUR_NAMED_ARGS_4 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4
        #define DETOUR_NAMED_ARGS_5 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5
        #define DETOUR_NAMED_ARGS_6 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p6
        #define DETOUR_NAMED_ARGS_7 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p7
        #define DETOUR_NAMED_ARGS_8 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p8
        #define DETOUR_NAMED_ARGS_9 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p9
        #define DETOUR_NAMED_ARGS_10 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p10
        #define DETOUR_NAMED_ARGS_11 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p11
        #define DETOUR_NAMED_ARGS_12 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p12
        #define DETOUR_NAMED_ARGS_13 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p13
        #define DETOUR_NAMED_ARGS_14 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter14>::Result p14
        #define DETOUR_NAMED_ARGS_15 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter14>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter15>::Result p15
        #define DETOUR_NAMED_ARGS_16 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter14>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter15>::Result p15, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter16>::Result p16
        #define DETOUR_NAMED_ARGS_17 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter14>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter15>::Result p15, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter16>::Result p16, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter17>::Result p17
        #define DETOUR_NAMED_ARGS_18 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter14>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter15>::Result p15, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter16>::Result p16, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter17>::Result p17, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter18>::Result p18
        #define DETOUR_NAMED_ARGS_19 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter14>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter15>::Result p15, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter16>::Result p16, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter17>::Result p17, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter18>::Result p18, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter19>::Result p19
        #define DETOUR_NAMED_ARGS_20 typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter1>::Result p1, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter2>::Result p2, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter3>::Result p3, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter4>::Result p4, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter5>::Result p5, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter6>::Result p6, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter7>::Result p7, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter8>::Result p8, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter9>::Result p9, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter10>::Result p10, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter11>::Result p11, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter12>::Result p12, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter13>::Result p13, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter14>::Result p14, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter15>::Result p15, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter16>::Result p16, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter17>::Result p17, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter18>::Result p18, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter19>::Result p19, typename WEX::Common::MakeReference<typename WEX::Common::ParameterTypes<TDetourPrototype>::Parameter20>::Result p20

        #define DETOUR_FUNCTION_METHOD(PARAMCOUNT) \
        typename WEX::Common::ParameterTypes<TDetourPrototype>::ReturnType Function(BUILD_VARIABLE_NAME(DETOUR_NAMED_ARGS_, PARAMCOUNT)) \
        { \
            WEX_ASSERT(m_detourFunction.IsValid(), L"DetourFunction is about to invoke an invalid functor."); \
            return (m_detourFunction)(BUILD_VARIABLE_NAME(PARAMETER_ARGS_, PARAMCOUNT)); \
        }

        // Builds out each Function(...) method that gets invoked by the DetourShim
        DETOUR_FUNCTION_METHOD(0)
        DETOUR_FUNCTION_METHOD(1)
        DETOUR_FUNCTION_METHOD(2)
        DETOUR_FUNCTION_METHOD(3)
        DETOUR_FUNCTION_METHOD(4)
        DETOUR_FUNCTION_METHOD(5)
        DETOUR_FUNCTION_METHOD(6)
        DETOUR_FUNCTION_METHOD(7)
        DETOUR_FUNCTION_METHOD(8)
        DETOUR_FUNCTION_METHOD(9)
        DETOUR_FUNCTION_METHOD(10)
        DETOUR_FUNCTION_METHOD(11)
        DETOUR_FUNCTION_METHOD(12)
        DETOUR_FUNCTION_METHOD(13)
        DETOUR_FUNCTION_METHOD(14)
        DETOUR_FUNCTION_METHOD(15)
        DETOUR_FUNCTION_METHOD(16)
        DETOUR_FUNCTION_METHOD(17)
        DETOUR_FUNCTION_METHOD(18)
        DETOUR_FUNCTION_METHOD(19)
        DETOUR_FUNCTION_METHOD(20)
    };
} /* namespace Private */ } /* namespace Mock10 */

#pragma pop_macro("SEALED")
#pragma pop_macro("Assert")
